package com.hsh.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hsh.config.jwt.JWTToken;
import com.hsh.entity.DbMenu;
import com.hsh.entity.DbRole;
import com.hsh.entity.DbRole2menu;
import com.hsh.entity.DbUser;
import com.hsh.entity.DbUser2role;
import com.hsh.mapper.DbUserMapper;
import com.hsh.service.IDbDepartmentService;
import com.hsh.service.IDbMenuService;
import com.hsh.service.IDbRole2menuService;
import com.hsh.service.IDbRoleService;
import com.hsh.service.IDbUser2deptService;
import com.hsh.service.IDbUser2roleService;
import com.hsh.service.IDbUserService;
import com.hsh.tools.AcCollectionUtils;
import com.hsh.tools.AddressUtil;
import com.hsh.tools.IPUtil;
import com.hsh.tools.JWTUtils;
import com.hsh.tools.Md5Utils;
import com.hsh.tools.convert.DeptConvert;
import com.hsh.tools.decision.AccountTypeEnum;
import com.hsh.tools.decision.LoginTypEnums;
import com.hsh.tools.handler.BusinessException;
import com.hsh.vo.dto.ActiveUser;
import com.hsh.vo.param.UserLoginParam;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 黄思海
 * @since 2021-06-26
 */
@Service
public class DbUserServiceImpl extends ServiceImpl<DbUserMapper, DbUser> implements IDbUserService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
    // 人力行政的部门id
    private final static String SYS_RLXZB = "SYS_RLXZB";
    private final static String SYS_RLXZB_USER_NAME = "陆欣慧";
    private final static String SYS_RLXZB_DEPT_NAME = "人力行政部";
    private final static Integer SYS_DEPT_SUPPER = 3;
    private final static String lastCs = "fq";

    @Autowired
    protected HttpServletRequest request;
    //    @Autowired
//    private RedisUtil redisUtil;
    @Autowired
    private IDbUserService userService;
    @Autowired
    IDbUser2roleService user2roleService;
    @Autowired
    IDbRoleService roleService;
    @Autowired
    IDbRole2menuService role2menuService;
    @Autowired
    IDbMenuService menuService;
    @Autowired
    IDbDepartmentService dbDepartmentService;
    @Autowired
    IDbUser2deptService user2deptService;
    @Autowired
    IDbDepartmentService departmentService;
    @Autowired
    DbUserMapper userMapper;
    @Autowired
    DeptConvert deptConvert;


    @Override
    public List<DbUser> findUserByUsernameMobile(String usernameMobile) {
        QueryWrapper<DbUser> ew = new QueryWrapper<>();
        ew.and(i -> i.eq("username", usernameMobile).or().eq("mobile", usernameMobile)).orderByDesc("CREATE_TIME");
        return this.list(ew);
    }

    @Override
    public boolean checkUserDept(String userId) {
        return baseMapper.checkUserDept(userId) > 0;
    }

    @Override
    public List<DbRole> findRolesByUserId(String userId) {
        DbUser user = this.getById(userId);
        if (Objects.isNull(user)) {
            logger.error("current user is not exists --> user_id = {}", userId);
            throw new BusinessException("当前用户信息不存在！");
        }
        List<DbUser2role> user2roleList = user2roleService.list(new QueryWrapper<DbUser2role>().eq("user_id", user.getUserId()));
        if (AcCollectionUtils.isNotEmpty(user2roleList)) {
            return user2roleList.stream().map(item -> roleService.getById(item.getRoleId())).collect(Collectors.toList());
        }
        throw new BusinessException("未查询到该用户的角色信息，请联系管理员！");
    }

    @Override
    public List<DbMenu> findMenuByRoles(List<DbRole> roles) {
        if (AcCollectionUtils.isNotEmpty(roles)) {
            // 存放用户的菜单id(唯一)
            Set<Integer> menuIds = new HashSet<>();
            for (DbRole role : roles) {
                List<DbRole2menu> role2menus = role2menuService.list(new QueryWrapper<DbRole2menu>().eq("role_id", role.getRoleId()));
                if (AcCollectionUtils.isNotEmpty(role2menus)) {
                    for (DbRole2menu item : role2menus) {
                        menuIds.add(item.getMenuId());
                    }
                }
            }
            // 该用户所有的菜单
            if (AcCollectionUtils.isNotEmpty(menuIds)) {
                return menuIds.stream().map(menuId -> menuService.getById(menuId)).filter(Objects::nonNull).collect(Collectors.toList());
            }
        }
        throw new BusinessException("未查询到该角色的菜单信息，请联系管理员！");
    }

    @Override
    public String checkLogin(UserLoginParam param) {
        if (param.getLoginType().equals(LoginTypEnums.LOGIN_MOBILE_PASSWORD.getCode()) || param.getLoginType().equals(LoginTypEnums.LOGIN_USERNAME_PASSWORD.getCode())) {
//            // 手机号密码登录 或者 用户名密码登录
//            String loginCode = (String) redisUtil.get(FinalData.LOGIN_CODE_FLAG);
//            if (loginCode == null) {
//                throw new BusinessException("图片验证码为空");
//            }
//            if (Objects.equals(param.getVerifyCode(),loginCode.trim())) {
//                String token = login(param);
//            }
            return login(param);
        } else if (param.getLoginType().equals(LoginTypEnums.LOGIN_MOBILE_VERITY_CODE.getCode())) {
            // TODO 手机验证码登录
//            token = userService.loginPhone("17773792865", "666666", loginType);
        } else if (param.getLoginType().equals(LoginTypEnums.LOGIN_EMAIL.getCode())) {
            // TODO 邮箱登录

        } else if (param.getLoginType().equals(LoginTypEnums.LOGIN_FACE.getCode())) {
            // TODO 人脸登录
        }
        throw new BusinessException("请使用合法登录方式登入！");
    }

    /**
     * 返回当前登录者
     */
    public DbUser getCurrentLoginUser(UserLoginParam param) {
        List<DbUser> userList = findUserByUsernameMobile(param.getUsernameMobile());
        if (AcCollectionUtils.isEmpty(userList)) {
            throw new BusinessException("该账户不存在！");
        }
        if (userList.size() > 1) {
            throw new BusinessException("此账户信息存在多条，请联系相关技术人员！");
        }
        DbUser currentUser = userList.get(0);
        // 判断其对应部门
        boolean exist = userService.checkUserDept(currentUser.getUserId());
        if (!exist) {
            throw new BusinessException("该用户尚未分配部门，请联系管理员！");
        }
        if (Objects.equals(AccountTypeEnum.NO_ACTIVATED.getCode(), currentUser.getActivationStatus())) {
            throw new BusinessException("该账号暂未激活！");
        }
        if (Objects.equals(AccountTypeEnum.DELETED.getCode(), currentUser.getDelFlag())) {
            throw new BusinessException("该管理员账号不存在(已逻辑删除),请联系管理员！");
        }
        if (Objects.equals(AccountTypeEnum.ACCOUNT_ABNORMAL.getCode(), currentUser.getAccountStatus())) {
            throw new BusinessException("该账号异常,请联系管理员！");
        }
        return currentUser;
//        List<DbUser> userList = findUserByUsernameMobile(param.getUsernameMobile());
//        if (AcCollectionUtils.isEmpty(userList)) {
//            throw new BusinessException("该账户不存在！");
//        }
//        if (userList.size() > 1) {
//            throw new BusinessException("此账户信息存在多条，请联系相关技术人员！");
//        }
//        DbUser currentUser = userList.get(0);
//        // 判断其对应部门
//        boolean exist = userService.checkUserDept(currentUser.getUserId());
//        if (!exist) {
//            throw new AccountException("该用户尚未分配部门，请联系管理员！");
//        }
//
//        if (Objects.equals(AccountTypeEnum.NO_ACTIVATED.getCode(), currentUser.getActivationStatus())) {
//            throw new LockedAccountException("该账号暂未激活！");
//        }
//        if (Objects.equals(AccountTypeEnum.DELETED.getCode(), currentUser.getDelFlag())) {
//            throw new AccountException("该管理员账号不存在(已逻辑删除),请联系管理员！");
//        }
//        if (Objects.equals(AccountTypeEnum.ACCOUNT_ABNORMAL.getCode(), currentUser.getAccountStatus())) {
//            throw new AccountException("该账号异常,请联系管理员！");
//        }
//        return currentUser;
    }

    @Override
    public String login(UserLoginParam param) {
        // todo 开始登录
        DbUser user = getCurrentLoginUser(param);
        // 认证通过 过滤 对应菜单和权限
        ActiveUser activeUser = new ActiveUser();
        List<DbRole> roles = userService.findRolesByUserId(user.getUserId());
        // 查询用户的所有菜单(包括了菜单和按钮)
        List<DbMenu> menus = userService.findMenuByRoles(roles);
        Set<String> urls = new HashSet<>();//该用户所拥有的访问路径
        Set<String> perms = new HashSet<>();//该用户所拥有的权限
        if (AcCollectionUtils.isNotEmpty(menus)) {
            for (DbMenu menu : menus) {
                String url = menu.getUrl();
                String per = menu.getPerms();
                if (menu.getType() == 0 && StrUtil.isNotEmpty(url)) {
                    urls.add(menu.getUrl());
                }
                if (menu.getType() == 1 && StrUtil.isNotEmpty(per)) {
                    perms.add(menu.getPerms());
                }
            }
        }

        activeUser.setUser(user);
        activeUser.setLoginType(param.getLoginType());
        activeUser.setRoles(roles);
        activeUser.setUrls(urls);
        activeUser.setMenus(menus);
        activeUser.setPermissions(perms);
        activeUser.setUsername(user.getUsername());
        activeUser.setNickname(user.getNickname());
        String ip = IPUtil.getIp();
        activeUser.setHost(ip);
        activeUser.setSystemHost(ip);
        activeUser.setLocation(AddressUtil.getCityInfo(ip));
        activeUser.setDeptFlag(true);

        // Danger
        activeUser.setPassword(user.getPassword());
        activeUser.setSalt(user.getSalt());
        activeUser.setUserId(user.getUserId());

        // 盐
        String dbPwd = Md5Utils.md5Encryption(param.getPassword(), user.getSalt()).trim();
        // 生成Token
        String token = JWTUtils.signLogin(activeUser, dbPwd);
        // 返回token
        activeUser.setToken(token);
        // TODO 登录日志
        // userService.addLoginLogs(request);//写入登录日志  登录日志
        JWTToken jwtToken = new JWTToken(token);
        try {
            SecurityUtils.getSubject().login(jwtToken);
        } catch (BusinessException be) {
            logger.error(be.getMessage());
            throw new BusinessException(be.getMessage());
        } catch (UnknownAccountException uae) {
            logger.error(uae.getMessage());
            throw new UnknownAccountException("账户不存在~~");
        } catch (IncorrectCredentialsException ice) {
            logger.error(ice.getMessage());
            throw new IncorrectCredentialsException("密码错误~~");
        } catch (LockedAccountException lae) {
            logger.error(lae.getMessage());
            throw new LockedAccountException("账户被锁~~");
        } catch (AuthenticationException e) {
            logger.error(e.getMessage());
            throw new AuthenticationException("Token认证失败，请重新登录！");
//            throw new AuthenticationException(e.getMessage());
        }
        return token;
    }
}
